#include "svr_skeleton.h"

struct cnfg_info cnfg_info;
struct stat_info stat_info;

extern int svr_init(char *passwd);
extern int svr_done();
extern int worker_start();
extern int listener_start();

static int _cnfg(char *argv0)
{/*{{{*/
    int res;

    // SERVER_NAME
    char svr_bin[LONG_FILE_NM_SIZE+1];
    sprintf(svr_bin, "svr_%s", SERVER_NAME);

    char *svcenv_dir=getenv("SVCENV_DIR");
    if(!svcenv_dir)
    {
        fprintf(stderr, "%s: SVCENV_DIR not set", SERVER_NAME);
        return(-1);
    }
    char *svcenv_cnfg=getenv("SVCENV_CNFG");
    if(!svcenv_cnfg)
    {
        fprintf(stderr, "%s: SVCENV_CNFG not set", SERVER_NAME);
        return(-1);
    }

    /*----- cnfg -----*/
    CNFG cnfg;
    struct cnfg_property property;
    res=cnfg_load(svcenv_cnfg, &cnfg);
    if(res)
    {
        if(res > 0)
            fprintf(stderr, "%s: svcenv.cnfg line %d error\n",
                    SERVER_NAME, res);
        else
            fprintf(stderr, "%s: load svcenv.cnfg fail, errcode:%d\n",
                    SERVER_NAME, res);
        return(-1);
    }

    // ERRLOG
    sprintf(cnfg_info._errlog_.location, "%s/log", svcenv_dir);
    res=cnfg_get_property(cnfg, "ERRLOG", "LOCATION", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr, "%s: get ERRLOG.LOCATION fail, res:%d\n",
                    SERVER_NAME, res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
        {
            if(property.value[0] == '/')
                strcpy(cnfg_info._errlog_.location, property.value);
            else
                sprintf(cnfg_info._errlog_.location, "%s/%s",
                        svcenv_dir, property.value);
        }
    }
    res=init_errlog(argv0, cnfg_info._errlog_.location);
    if(res)
    {
        fprintf(stderr, "%s: init_errlog fail, res:%d\n",
                SERVER_NAME, res);
        return(-1);
    }

    // IPCKEY
    res=cnfg_get_property(cnfg, "GLOBAL", "IPCKEY", 0, &property);
    if(res)
    {
        fprintf(stderr, "%s: get IPCKEY in svcenv.cnfg fail\n",
                SERVER_NAME);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || !str_is_dec(property.value))
    {
        fprintf(stderr, "%s: IPCKEY invalid in svcenv.cnfg\n",
                SERVER_NAME);
        return(-1);
    }
    cnfg_info.ipckey=atoi(property.value);

    // SERVER
    res=cnfg_get_subproperty(cnfg, "SERVER", svr_bin, "DB",
            0, &property);
    if(res)
    {
        fprintf(stderr, "%s: get SERVER.%s.DB in svcenv.cnfg fail\n",
                SERVER_NAME, svr_bin);
        return(-1);
    }
    if(BUF_IS_CLR(property.value))
    {
        fprintf(stderr, "%s: SERVER.%s.DB in svcenv.cnfg invalid\n",
                SERVER_NAME, svr_bin);
        return(-1);
    }
    strcpy(cnfg_info._db_.name, property.value);
    cnfg_info.start=1;
    res=cnfg_get_subproperty(cnfg, "SERVER", svr_bin, "START",
            0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
        fprintf(stderr,
                "%s: get SERVER.%s.START in svcenv.cnfg fail\n",
                SERVER_NAME, svr_bin);
        return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
        {
            cnfg_info.start=atoi(property.value);
            if(cnfg_info.start == 0)
                cnfg_info.start=1;
        }
    }

    /*--- SVCNODE ---*/
    res=cnfg_get_subproperty(cnfg, "SVCNODE", "PASSWD", "ADDR",
            0, &property);
    if(res)
    {
        fprintf(stderr,
                "%s: get SVCNODE.PASSWD.ADDR in svcenv.cnfg fail\n",
                SERVER_NAME);
        return(-1);
    }
    if(BUF_IS_CLR(property.value))
    {
        fprintf(stderr,
                "%s: SVCNODE.PASSWD.ADDR in svcenv.cnfg invalid\n",
                SERVER_NAME);
        return(-1);
    }
    strcpy(cnfg_info._sn_.passwd_addr, property.value);

    res=cnfg_get_subproperty(cnfg, "SVCNODE", "SECURE", "ADDR",
            0, &property);
    if(res)
    {
        fprintf(stderr,
                "%s: get SVCNODE.SECURE.ADDR in svcenv.cnfg fail\n",
                SERVER_NAME);
        return(-1);
    }
    if(BUF_IS_CLR(property.value))
    {
        fprintf(stderr,
                "%s: SVCNODE.SECURE.ADDR in svcenv.cnfg invalid\n",
                SERVER_NAME);
        return(-1);
    }
    strcpy(cnfg_info._sn_.secure_addr, property.value);

    res=cnfg_get_subproperty(cnfg, "SVCNODE", "MAILFWD", "ADDR",
            0, &property);
    if(res)
    {
        fprintf(stderr,
                "%s: get SVCNODE.MAILFWD.ADDR in svcenv.cnfg fail\n",
                SERVER_NAME);
        return(-1);
    }
    if(BUF_IS_CLR(property.value))
    {
        fprintf(stderr,
                "%s: SVCNODE.MAILFWD.ADDR in svcenv.cnfg invalid\n",
                SERVER_NAME);
        return(-1);
    }
    strcpy(cnfg_info._sn_.mailfwd_addr, property.value);

    /*--- DB ---*/
    // USER
    res=cnfg_get_subproperty(cnfg, "DB", cnfg_info._db_.name, "USER",
            0, &property);
    if(res)
    {
        fprintf(stderr, "%s: get DB.%s.USER in svcenv.cnfg fail\n",
                SERVER_NAME, cnfg_info._db_.name);
        return(-1);
    }
    if(BUF_IS_CLR(property.value))
    {
        fprintf(stderr, "%s: DB.%s.USER in svcenv.cnfg invalid\n",
                SERVER_NAME, cnfg_info._db_.name);
        return(-1);
    }
    strcpy(cnfg_info._db_.user, property.value);
    // DATABASE
    res=cnfg_get_subproperty(cnfg, "DB", cnfg_info._db_.name, "DATABASE",
            0, &property);
    if(res)
    {
        fprintf(stderr, "%s: get DB.%s.DATABASE in svcenv.cnfg fail\n",
                SERVER_NAME, cnfg_info._db_.name);
        return(-1);
    }
    if(BUF_IS_CLR(property.value))
    {
        fprintf(stderr, "%s: DB.%s.DATABASE in svcenv.cnfg invalid\n",
                SERVER_NAME, cnfg_info._db_.name);
        return(-1);
    }
    strcpy(cnfg_info._db_.database, property.value);
    // HOST
    CLR_BUF(cnfg_info._db_.host);
    res=cnfg_get_subproperty(cnfg, "DB", cnfg_info._db_.name, "HOST",
            0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr, "%s: get DB.%s.HOST in svcenv.cnfg fail\n",
                    SERVER_NAME, cnfg_info._db_.name);
            return(-1);
        }
    }
    else
    {
        if(BUF_IS_CLR(property.value))
        {
            fprintf(stderr, "%s: DB.%s.HOST in svcenv.cnfg invalid\n",
                    SERVER_NAME, cnfg_info._db_.name);
            return(-1);
        }
        strcpy(cnfg_info._db_.host, property.value);
    }


    cnfg_free(cnfg);

    return(0);
}/*}}}*/

static int _get_dbpasswd(char *passwd)
{/*{{{*/
    SVCNODE sn;
    char request[100];
    char respond[100];
    char *p;
    char *curr;
    char *rtn;
    int res;

    res=sn_create(cnfg_info._sn_.passwd_addr, SN_MODE_ONESHOT, &sn);
    if(res)
    {
        fprintf(stderr,
                "%s: svcnode init for sn_passwd fail, errcode:%d\n",
                SERVER_NAME, res);
        return(-1);
    }
    CLR_BUF(request);
    para_put_item(request, cnfg_info._db_.name);
    para_put_item(request, cnfg_info._db_.user);
    res=sn_call(sn, "GETDBPASSWD", request, respond);
    if(res)
    {
        fprintf(stderr,
                "%s: call to sn_passwd fail, errcode:%d\n",
                SERVER_NAME, res);
        return(-1);
    }
    curr=respond;
    rtn=para_get_item(respond, &curr);
    if(!rtn || strcmp(rtn, SOAR_ERR_OK))
    {
        fprintf(stderr, "%s: get db(%s:%s) passwd fail, errcode:%s\n",
                SERVER_NAME, cnfg_info._db_.name, cnfg_info._db_.user,
                rtn?rtn:"null");
        return(-1);
    }
    p=para_get_item(respond, &curr);
    if(!p)
    {
        fprintf(stderr, "%s: db(%s:%s) passwd invalid\n",
                SERVER_NAME, cnfg_info._db_.name, cnfg_info._db_.user);
        return(-1);
    }
    strcpy(passwd, p);
    //printf("passwd: %s\n", dbpasswd);
    sn_free(sn);

    return(0);
}/*}}}*/

static int _register()
{/*{{{*/
#define _REGISTER_TIMEOUT       2
    char buf[200];
    int rtn;
    int res;

    char *msg;
    int msg_size;
    ALLOC_MULTI_DOERR(msg, char, SOCK_MSG_SIZE,
            sprintf(buf, "%s: alloc msg fail", SERVER_NAME);
            fprintf(stderr, "%s\n", buf); errlog(buf);
            return(-1));
    CLR_BUF(msg);
    para_put_item(msg, SERVER_NAME);
    para_put_item_int(msg, SVC_MAP_SIZE);
    int i;
    for(i=0; i<SVC_MAP_SIZE; ++i)
        para_put_item(msg, SVC_MAP[i].name);
    para_put_item_int(msg, getpid());
    char addr[LONG_FILE_NM_SIZE+1];
    sprintf(addr, "seagent_register_%d", cnfg_info.ipckey);
    SOCKET sock=sock_local_connect(addr);
    if(sock == INVALID_SOCKET)
    {
        sprintf(buf, "%s: connect to agent fail", SERVER_NAME);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        rtn=-1; goto GO_OUT;
    }
    msg_size=strlen(msg);
    res=sock_write(sock, (unsigned char *)msg, &msg_size,
            _REGISTER_TIMEOUT, WRAP);
    if(res)
    {
        sprintf(buf, "%s: register to agent, write fail", SERVER_NAME);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        rtn=-1; goto GO_OUT;
    }
    res=sock_read(sock, (unsigned char *)msg, &msg_size,
            _REGISTER_TIMEOUT, WRAP);
    if(res)
    {
        sprintf(buf, "%s: register to agent, read fail", SERVER_NAME);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        rtn=-1; goto GO_OUT;
    }
    char *curr=msg;
    char *errcode=para_get_item(msg, &curr);
    if(!errcode || strcmp(errcode, SOAR_ERR_OK))
    {
        sprintf(buf, "%s: register to agent fail, errcode:%s",
                SERVER_NAME, errcode?errcode:"null");
        fprintf(stderr, "%s\n", buf); errlog(buf);
        rtn=-1; goto GO_OUT;
    }
    rtn=0;
    sprintf(buf, "%s: register succeed", SERVER_NAME);
    fprintf(stderr, "%s\n", buf); errlog(buf);

GO_OUT:
    sock_close(sock);
    free(msg);
    return(rtn);
}/*}}}*/

static int _start()
{/*{{{*/
    char buf[200];

    sig_ignore(SIGPIPE);
    ep_init();
    ossl_init_mt();

    // get database passwd
    char passwd[FILE_NM_SIZE+1];
    if(_get_dbpasswd(passwd))
    {
        return(-1);
    }

    // server init
    if(svr_init(passwd))
    {
        sprintf(buf, "%s: svr_init fail", SERVER_NAME);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    sprintf(buf, "%s: svr_init succeed", SERVER_NAME);
    fprintf(stderr, "%s\n", buf); errlog(buf);

    // register to agent
    if(_register())
    {
        return(-1);
    }

    if(worker_start())
    {
        sprintf(buf, "%s: worker start fail", SERVER_NAME);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }
    if(listener_start())
    {
        sprintf(buf, "%s: listener start fail", SERVER_NAME);
        fprintf(stderr, "%s\n", buf); errlog(buf);
        return(-1);
    }

    svr_done();

    return(0);
}/*}}}*/

int main(int argc, char *argv[])
{/*{{{*/
    if(daemon(1, 1) == -1)
    {
        fprintf(stderr, "daemon fail: %d\n", get_last_error(NULL)); 
        return(1);
    }
    if(_cnfg(argv[0])) return(-1);
    _start();
    return(0);
}/*}}}*/
